home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / fs / read.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  17KB  |  482 lines

  1. /* This file contains the heart of the mechanism used to read (and write)
  2.  * files.  Read and write requests are split up into chunks that do not cross
  3.  * block boundaries.  Each chunk is then processed in turn.  Reads on special
  4.  * files are also detected and handled.
  5.  *
  6.  * The entry points into this file are
  7.  *   do_read:     perform the READ system call by calling read_write
  8.  *   read_write: actually do the work of READ and WRITE
  9.  *   read_map:     given an inode and file position, look up its zone number
  10.  *   rw_user:     call the kernel to read and write user space
  11.  *   read_ahead: manage the block read ahead business
  12.  */
  13.  
  14. #include "fs.h"
  15. #include <fcntl.h>
  16. #include <minix/com.h>
  17. #include "buf.h"
  18. #include "file.h"
  19. #include "fproc.h"
  20. #include "inode.h"
  21. #include "param.h"
  22. #include "super.h"
  23.  
  24. #define FD_MASK          077    /* max file descriptor is 63 */
  25.  
  26. PRIVATE message umess;        /* message for asking SYSTASK for user copy */
  27.  
  28. FORWARD int rw_chunk();
  29.  
  30. /*===========================================================================*
  31.  *                do_read                         *
  32.  *===========================================================================*/
  33. PUBLIC int do_read()
  34. {
  35.   return(read_write(READING));
  36. }
  37.  
  38.  
  39. /*===========================================================================*
  40.  *                read_write                     *
  41.  *===========================================================================*/
  42. PUBLIC int read_write(rw_flag)
  43. int rw_flag;            /* READING or WRITING */
  44. {
  45. /* Perform read(fd, buffer, nbytes) or write(fd, buffer, nbytes) call. */
  46.  
  47.   register struct inode *rip;
  48.   register struct filp *f;
  49.   register off_t bytes_left, f_size;
  50.   register unsigned off, cum_io;
  51.   register int oflags;
  52.   off_t position;
  53.   int r, chunk, mode_word, usr, seg, block_spec, char_spec, regular;
  54.   struct filp *wf;
  55.  
  56.   /* MM loads segments by putting funny things in upper 10 bits of 'fd'. */
  57.   if (who == MM_PROC_NR && (fd & (~BYTE)) ) {
  58.     usr = (fd >> 8) & BYTE;
  59.     seg = (fd >> 6) & 03;
  60.     fd &= FD_MASK;        /* get rid of user and segment bits */
  61.   } else {
  62.     usr = who;        /* normal case */
  63.     seg = D;
  64.   }
  65.  
  66.   /* If the file descriptor is valid, get the inode, size and mode. */
  67. #if (CHIP == INTEL)
  68.   if (who != MM_PROC_NR)    /* only MM > 32K */
  69. #endif
  70.  
  71.   if (nbytes < 0) return(EINVAL);
  72.   if ( (f = get_filp(fd)) == NIL_FILP) return(err_code);
  73.   if ( ((f->filp_mode) & (rw_flag == READING ? R_BIT : W_BIT)) == 0)
  74.     return(EBADF);
  75.   if (nbytes == 0) return(0);    /* so char special files need not check for 0*/
  76.   position = f->filp_pos;
  77.   if (position < 0 || position > MAX_FILE_POS) return(EINVAL);
  78.   oflags = f->filp_flags;
  79.   rip = f->filp_ino;
  80.   f_size = rip->i_size;
  81.   r = OK;
  82.   cum_io = 0;
  83.   mode_word = rip->i_mode & I_TYPE;
  84.   regular = mode_word == I_REGULAR || mode_word == I_NAMED_PIPE;
  85.  
  86.   char_spec = (mode_word == I_CHAR_SPECIAL ? 1 : 0);
  87.   block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0);
  88.   if (block_spec && f_size == 0) f_size = MAX_P_LONG;
  89.   rdwt_err = OK;        /* set to EIO if disk error occurs */
  90.  
  91.   /* Check for character special files. */
  92.   if (char_spec) {
  93.     if ((r = dev_io(rw_flag, oflags & O_NONBLOCK, (dev_t) rip->i_zone[0],
  94.                  position, nbytes, who, buffer)) >= 0) {
  95.         cum_io = r;
  96.         position += r;
  97.         r = OK;
  98.     }
  99.   } else {
  100.     if (rw_flag == WRITING && block_spec == 0) {
  101.         /* Check in advance to see if file will grow too big. */
  102.         if (position > get_super(rip->i_dev)->s_max_size - nbytes )
  103.             return(EFBIG);
  104.  
  105.         /* check for O_APPEND flag */
  106.         if (oflags & O_APPEND) position = f_size;
  107.  
  108.         /* Clear the zone containing present EOF if hole about
  109.          * to be created.  This is necessary because all unwritten
  110.          * blocks prior to the EOF must read as zeros.
  111.          */
  112.         if (position > f_size) clear_zone(rip, f_size, 0);
  113.     }
  114.  
  115.     /* Pipes are a little different.  Check. */
  116.     if (rip->i_pipe &&
  117.         (r = pipe_check(rip, rw_flag, oflags, nbytes, position)) <= 0)
  118.         return r;
  119.  
  120.     /* Split the transfer into chunks that don't span two blocks. */
  121.     while (nbytes != 0) {
  122.         off = position % BLOCK_SIZE;    /* offset within a block */
  123.         chunk = MIN(nbytes, BLOCK_SIZE - off);
  124.         if (chunk < 0) chunk = BLOCK_SIZE - off;
  125.  
  126.         if (rw_flag == READING || (block_spec && rw_flag == WRITING)) {
  127.             bytes_left = f_size - position;
  128.             if (position >= f_size) break;    /* we are beyond EOF */
  129.             if (chunk > bytes_left) chunk = bytes_left;
  130.         }
  131.  
  132.         /* Read or write 'chunk' bytes. */
  133.         r = rw_chunk(rip, position, off, chunk, nbytes, rw_flag,
  134.                                  buffer, seg, usr);
  135.         if (r != OK) break;    /* EOF reached */
  136.         if (rdwt_err < 0) break;
  137.  
  138.         /* Update counters and pointers. */
  139.         buffer += chunk;    /* user buffer address */
  140.         nbytes -= chunk;    /* bytes yet to be read */
  141.         cum_io += chunk;    /* bytes read so far */
  142.         position += chunk;    /* position within the file */
  143.     }
  144.   }
  145.  
  146.   /* On write, update file size and access time. */
  147.   if (rw_flag == WRITING) {
  148.     if (regular || mode_word == I_DIRECTORY) {
  149.         if (position > f_size) rip->i_size = position;
  150.         rip->i_update = MTIME; /* mark mtime for update later */
  151.         rip->i_dirt = DIRTY;
  152.     }
  153.   } else {
  154.     if (rip->i_pipe && position >= rip->i_size) {
  155.         /* Reset pipe pointers. */
  156.         rip->i_size = 0;    /* no data left */
  157.         position = 0;        /* reset reader(s) */
  158.         if ( (wf = find_filp(rip, W_BIT)) != NIL_FILP) wf->filp_pos =0;
  159.     }
  160.   }
  161.   f->filp_pos = position;
  162.  
  163.   /* Check to see if read-ahead is called for, and if so, set it up. */
  164.   if (rw_flag == READING && rip->i_seek == NO_SEEK && position % BLOCK_SIZE== 0
  165.         && (regular || mode_word == I_DIRECTORY)) {
  166.     rdahed_inode = rip;
  167.     rdahedpos = position;
  168.   }
  169.   rip->i_seek = NO_SEEK;
  170.  
  171.   if (rdwt_err != OK) r = rdwt_err;    /* check for disk error */
  172.   if (rdwt_err == END_OF_FILE) r = cum_io;
  173.   return(r == OK ? cum_io : r);
  174. }
  175.  
  176.  
  177. /*===========================================================================*
  178.  *                rw_chunk                     *
  179.  *===========================================================================*/
  180. PRIVATE int rw_chunk(rip, position, off, chunk, left, rw_flag, buff, seg, usr)
  181. register struct inode *rip;    /* pointer to inode for file to be rd/wr */
  182. off_t position;            /* position within file to read or write */
  183. unsigned off;            /* off within the current block */
  184. int chunk;            /* number of bytes to read or write */
  185. unsigned left;            /* max number of bytes wanted after position */
  186. int rw_flag;            /* READING or WRITING */
  187. char *buff;            /* virtual address of the user buffer */
  188. int seg;            /* T or D segment in user space */
  189. int usr;            /* which user process */
  190. {
  191. /* Read or write (part of) a block. */
  192.  
  193.   register struct buf *bp;
  194.   register int r;
  195.   int dir, n, block_spec;
  196.   block_nr b;
  197.   dev_t dev;
  198.  
  199.   block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
  200.   if (block_spec) {
  201.     b = position/BLOCK_SIZE;
  202.     dev = (dev_t) rip->i_zone[0];
  203.   } else {
  204.     b = read_map(rip, position);
  205.     dev = rip->i_dev;
  206.   }
  207.  
  208.   if (!block_spec && b == NO_BLOCK) {
  209.     if (rw_flag == READING) {
  210.         /* Reading from a nonexistent block.  Must read as all zeros. */
  211.         bp = get_block(NO_DEV, NO_BLOCK, NORMAL);     /* get a buffer */
  212.         zero_block(bp);
  213.     } else {
  214.         /* Writing to a nonexistent block. Create and enter in inode. */
  215.         if ((bp = new_block(rip, position)) == NIL_BUF)return(err_code);
  216.     }
  217.   } else if (rw_flag == READING) {
  218.     /* Read and read ahead if convenient. */
  219.     bp = rahead(rip, b, position, left);
  220.   } else {
  221.     /* Normally an existing block to be partially overwritten is first read
  222.      * in.  However, a full block need not be read in.  If it is already in
  223.      * the cache, acquire it, otherwise just acquire a free buffer.
  224.      */
  225.     n = (chunk == BLOCK_SIZE ? NO_READ : NORMAL);
  226.     if (!block_spec && off == 0 && position >= rip->i_size) n = NO_READ;
  227.     bp = get_block(dev, b, n);
  228.   }
  229.  
  230.   /* In all cases, bp now points to a valid buffer. */
  231.   if (rw_flag == WRITING && chunk != BLOCK_SIZE && !block_spec &&
  232.                     position >= rip->i_size && off == 0)
  233.     zero_block(bp);
  234.   dir = (rw_flag == READING ? TO_USER : FROM_USER);
  235.   r = rw_user(seg, usr, (vir_bytes)buff, (vir_bytes)chunk, bp->b_data+off, dir);
  236.   if (rw_flag == WRITING) bp->b_dirt = DIRTY;
  237.   n = (off + chunk == BLOCK_SIZE ? FULL_DATA_BLOCK : PARTIAL_DATA_BLOCK);
  238.   put_block(bp, n);
  239.   return(r);
  240. }
  241.  
  242.  
  243. /*===========================================================================*
  244.  *                read_map                     *
  245.  *=======================